using Hotran.Audio;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Tilemaps;

namespace Roots
{
    public class RootsHandler : MonoBehaviour
    {
        [SerializeField] ScoreManager scoreManager;

        [SerializeField] ParticleSystem starEffect;
        [SerializeField] ParticleSystem[] pickEffects;

        [SerializeField] Transform root;

        [SerializeField] Tilemap rootsMap = null;
        [SerializeField] Tilemap obstaclesMap;
        [SerializeField] RootRuleTile[] rootTiles;

        [SerializeField] int[] rootDistThresholds;

        [SerializeField] int[] depthBgmThresholds;

        
        /// <summary>
        /// 放下初始树根
        /// </summary>
        public UnityEvent FirstRootPlaced;
        
        /// <summary>
        /// 初始根部位置
        /// </summary>
        public Transform Root => root;
        private Vector3Int rootPos;

        private int currentDepth = 0;

        //距离根部的距离
        private readonly Dictionary<Vector3Int, int> distToRoot = new();

        private void Awake()
        {
            rootPos = rootsMap.WorldToCell(root.position);
        }

        /// <summary>
        /// 存在障碍物
        /// </summary>
        /// <param name="pos"></param>
        /// <returns></returns>
        public bool HasObstacle(Vector3Int pos) =>
            obstaclesMap.HasTile(pos);

        /// <summary>
        /// 是否符合放置树根条件
        /// </summary>
        /// <param name="pos"></param>
        /// <returns></returns>
        public bool CanPlaceRoot(Vector3Int pos, out int neighborsCount)
        {
            neighborsCount = 0;
            if (pos.y > rootPos.y) return false;
            if (HasObstacle(pos)) return false;
            if (rootsMap.HasTile(pos)) return false;

            bool left = rootsMap.HasTile(pos - Vector3Int.right);
            bool right = rootsMap.HasTile(pos + Vector3Int.right);
            bool up = rootsMap.HasTile(pos + Vector3Int.up);
            bool down = rootsMap.HasTile(pos - Vector3Int.up);
            neighborsCount =
                Convert.ToInt32(left) +
                Convert.ToInt32(right) +
                Convert.ToInt32(up) +
                Convert.ToInt32(down);
            return neighborsCount == 1;
        }

        /// <summary>
        /// 收取资源并放下树根
        /// </summary>
        /// <param name="pos"></param>
        public bool PlaceRoot(Vector3Int pos, LayerMask objLayer)
        {
            if (!scoreManager.HasEnoughResources)
            {
                Debug.LogError("没资源了！");
                return false;
            }

            var cellPos = rootsMap.GetCellCenterWorld(pos);
            //获取资源
            var collider = Physics2D.OverlapPoint(cellPos, layerMask: objLayer);
            if (collider != null && collider.TryGetComponent(out Resource resource))
            {
                if (resource.isStar)
                {
                    starEffect.transform.position = cellPos;
                    starEffect.Play();
                }
                else
                {
                    var effect = pickEffects[resource.type];
                    if (!effect.isPlaying)
                    {
                        effect.transform.position = cellPos;
                        effect.Play();
                    }
                }
                AudioPlayer.Instance.PlaySound(resource.pickSound);
                scoreManager.AddScore(resource);
                Destroy(resource.gameObject);
            }

            UpdateDistance(pos);
            //放置树根
            rootsMap.SetTile(pos, DecideTileType(pos));
            scoreManager.ConsumeResource();
            UpdateDepth(pos);

            return true;
        }

        private void UpdateDepth(Vector3Int pos)
        {
            //更新深度
            var depth = Mathf.Abs(pos.y - rootPos.y);
            if (depth > currentDepth)
            {
                currentDepth = depth;
                for (int i = 0; i < depthBgmThresholds.Length; i++)
                {
                    if (currentDepth <= depthBgmThresholds[i])
                    {
                        AudioPlayer.Instance.SwitchBGM(i);
                        break;
                    }
                }
            }
        }

        public bool PlaceFirstRoot(Vector3Int pos)
        {
            if (pos != rootPos) return false;

            rootsMap.SetTile(rootPos, rootTiles[0]);
            distToRoot.Add(rootPos, 0);

            FirstRootPlaced?.Invoke();
            return true;
        }

        private RuleTile DecideTileType(Vector3Int pos)
        {
            for (int i = 0; i < rootDistThresholds.Length; i++)
            {
                if (distToRoot[pos] <= rootDistThresholds[i]) return rootTiles[i];
            }
            return rootTiles[rootTiles.Length - 1];
        }

        private Vector3Int? GetParent(Vector3Int pos)
        {
            Vector3Int neighborPos = pos - Vector3Int.right;
            if (rootsMap.HasTile(neighborPos)) return neighborPos;

            neighborPos = pos + Vector3Int.right;
            if (rootsMap.HasTile(neighborPos)) return neighborPos;

            neighborPos = pos + Vector3Int.up;
            if (rootsMap.HasTile(neighborPos)) return neighborPos;

            neighborPos = pos - Vector3Int.up;
            if (rootsMap.HasTile(neighborPos)) return neighborPos;

            return null;
        }

        private void UpdateDistance(Vector3Int newTilePos)
        {
            var parent = GetParent(newTilePos);
            if (parent == null) throw new Exception("Parent is null!");
            if (!distToRoot.ContainsKey(parent.Value))
                throw new Exception("Parent has no distance!");
            distToRoot.Add(newTilePos, distToRoot[parent.Value] + 1);
        }
    }
}